/*
 * Copyright 2011 Clean GWT
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.cleangwt.uibinder.rebind;

import java.util.List;

import com.cleangwt.uibinder.client.RequiresTemplate;
import com.cleangwt.uibinder.client.RequiresWebTemplate;
import com.cleangwt.uibinder.client.TemplatePanel;
import com.cleangwt.uibinder.client.UiField;
import com.cleangwt.uibinder.client.UiHtml;
import com.cleangwt.uibinder.client.UiTemplate;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.ClientBundle.Source;
import com.google.gwt.resources.client.TextResource;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;

/**
 * A writer for generating implementation methods of {@link RequiresTemplate}.
 * 
 * @author Jess
 * @version 1.0
 * @since 1.0
 */
public class TemplateRebindWriter {

  private static final String DEFAULT_TEMPLATE_SUFFIX = ".html";

  private final JClassType binderType;
  private final List<JField> uiFields;

  public TemplateRebindWriter(JClassType binderType) {
    this.binderType = binderType;
    this.uiFields = TemplateRebindHelper.findUiFields(binderType);
  }

  /**
   * Adds imports.
   * 
   * @param composer the composer
   */
  public void addImports(ClassSourceFileComposerFactory composer) {
    composer.addImport(TemplatePanel.class.getCanonicalName());
    composer.addImport(GWT.class.getCanonicalName());
    composer.addImport(ClientBundle.class.getCanonicalName());
    composer.addImport(Source.class.getCanonicalName());
    composer.addImport(TextResource.class.getCanonicalName());
    for (JField field : uiFields) {
      composer.addImport(field.getType().getQualifiedSourceName());
    }
  }

  /**
   * Generates implementation methods.
   * 
   * @param sw the source writer
   * @param className the output class name
   * @param binderType the binder type
   * @throws UnableToCompleteException
   */
  public void run(SourceWriter sw, String className) throws UnableToCompleteException {
    if (!binderType.isAnnotationPresent(UiHtml.class)) {
      createClientBundle(sw, binderType);
    }
    createCreateTemplate(sw, className, binderType);
  }

  /**
   * Creates the client bundler.
   * 
   * @param sw the source writer
   * @param binderType the binder type
   */
  private void createClientBundle(SourceWriter sw, JClassType binderType) {
    String template = binderType.getSimpleSourceName() + DEFAULT_TEMPLATE_SUFFIX;
    if (binderType.isAnnotationPresent(UiTemplate.class)) {
      UiTemplate templateSource = binderType.getAnnotation(UiTemplate.class);
      if (!templateSource.value().isEmpty()) {
        template = templateSource.value();
      }
    }
    sw.println("interface Resources extends ClientBundle{");
    sw.indent();
    sw.println("Resources INSTANCE = GWT.create(Resources.class);");
    sw.println("@Source(\"%s\")", template);
    sw.println("TextResource get();");
    sw.outdent();
    sw.print("}");
    sw.println();
  }

  /**
   * Creates the {@link RequiresWebTemplate#createTemplate()}.
   * 
   * @param sw the source writer
   * @param className the class name
   * @param binderType the binder type
   * @param uiFields the fields with {@link UiField}
   * @throws UnableToCompleteException
   */
  private void createCreateTemplate(SourceWriter sw, String className, JClassType binderType)
      throws UnableToCompleteException {
    List<JField> uiFields = TemplateRebindHelper.findUiFields(binderType);
    sw.println();
    sw.println("public TemplatePanel createTemplate(){", binderType.getSimpleSourceName());
    sw.indent();
    if (binderType.isAnnotationPresent(UiHtml.class)) {
      UiHtml cs = binderType.getAnnotation(UiHtml.class);
      sw.println("TemplatePanel template = new TemplatePanel(\"%s\");", cs.value());
    } else {
      // default by using template
      sw.println("TemplatePanel template = new TemplatePanel(Resources.INSTANCE.get().getText());");
    }
    TemplateRebindHelper.createNotNullAssertion(sw, uiFields);
    TemplateRebindHelper.createOrReplaceFields(sw, uiFields);
    sw.println();
    sw.println("return template;");
    sw.outdent();
    sw.println("}");
  }

}
